home *** CD-ROM | disk | FTP | other *** search
-
- /* 4.xBSD and AT&T V.3 documented entry points are
- ** #define ecvt(arg,ndigs,decexp,neg) cvt(arg,ndigs,decexp,neg,0)
- ** #define fcvt(arg,ndigs,decexp,neg) cvt(arg,ndigs,decexp,neg,1)
- ** and gcvt, for which a simplified version is given which
- ** does not strip trailing .0000
- ** Microsoft gcvt() has only 3 arguments (?)
- **
- ** Nota Bene:
- ** AT&T sense of 4th argument */
- typedef int LOGICAL;
- #include <math.h>
- #include "float.h"
-
- extern struct {
- double n[308];
- double p[DBL_MAX_10_EXP];
- } dp10_;
-
- char *ecvt(value, ndigit, decpt, sign)
- double value;
- int ndigit, *decpt, *sign;
- {
- char *cvt();
- return (cvt(value, ndigit, decpt, sign, 0 ));
- }
-
- char *fcvt(value, ndigit, decpt, sign)
- double value;
- int ndigit, *decpt, *sign;
- {
- char *cvt();
- return (cvt(value, ndigit, decpt, sign, 1 ));
- }
-
- char *cvt(arg, ndigs, decexp, neg, ffmt)
- register double arg;
- int ndigs, *decexp;
- LOGICAL *neg, ffmt;
- {
- static char buf[80]; /* shouldn't need more than 25 */
- long high, low; /* assumed wide enough for 9+ digits */
- #ifdef __STDC__
- #include <limits.h>
- #if (LONG_MAX < 999999999) /* uncomment #error if possible */
- /*#error "code assumes 9 digits fit in long"*/
- #endif
- #include <stdlib.h>
- #define split(a,b) (r=ldiv(a,b))
- #else
- typedef struct {
- long quot;
- long rem;
- } ldiv_t;
- #ifdef sun
- #define split(a,b) (r.rem=a-(r.quot=a/b)*b)
- #else
- #define split(a,b) (r.quot=a/b,r.rem=a%b)
- #endif
- #endif
- ldiv_t r;
- int scale, totdigs, scalarg, maxscale;
- char *bufptr;
- register double x, dri; /* accumulate powers of 10 */
- LOGICAL pneg;
- register int i;
- #define ODD(i) ((i)&1) /* like Pascal */
-
- *decexp = 3; /* so gcvt won't add 0's or exponent */
- #define isnan(arg) (arg != arg)
- if (isnan(arg))
- return "NaN"; /* Sun library has isnan(),isinf() * but IEEE
- compliant compiler would recognize defines *
- #define isinf(arg) (arg==1/0.) */
- arg = (*neg = (arg < 0)) ? -arg : arg; /* only gcvt() actually
- inserts '-' */
- if (arg >= DBL_MAX*2) {
- *decexp = 8;
- return "Infinity";
- }
- if (arg == 0) { /* don't force weird e format for 0 */
- *decexp = 1;
- return "0";
- }
- /* search in table can be used instead of log()
- ** need negative powers in table
- ** speed up search by using log10() to find approximate index */
- scalarg = (int) log10(arg) + (arg > 1); /* ceil() in line */
- if (scalarg >= DBL_MIN_10_EXP & scalarg <= DBL_MAX_10_EXP)
- scalarg += (arg >= dp10_.p[scalarg]) - (arg < dp10_.p[scalarg - 1]); /* adjust */
- if ((scale = ffmt ? ndigs : ndigs - scalarg) > (maxscale = 18 - scalarg)) {
- /* reduce ndigs for 18 max */
- ndigs += maxscale - scale;
- scale = maxscale;
- }
- if (scale >= 14) { /* extend range by splitting high end off
- first */
- if (scale - 14 <= DBL_MAX_10_EXP)
- arg *= dp10_.p[scale - 14];
- else { /* avoid overflow */
- arg *= dp10_.p[DBL_MAX_10_EXP / 2];
- arg *= dp10_.p[scale - 14 - DBL_MAX_10_EXP / 2];
- } /* can't compare accurately with original arg */
- low = arg = (arg - (high = arg)) * 1e5; /* split off 4 digits */
- high = high * 100000 + low; /* add 5 more */
- low = (arg - low) * 1e9 + .5; /* round off last 9 */
- } else if (scale < 9) { /* split low end off first */
- high = 0;
- if ((ndigs > 9) | ffmt) /* prevents violating table
- boundary */
- arg -= (high = arg / dp10_.p[9 - scale]) * dp10_.p[9 - scale];
- low = (scale < 0 ? arg / dp10_.p[-scale] : arg * dp10_.p[scale]) + .5;
- } else { /* 9 <= scale < 14 */
- arg *= dp10_.p[scale - 9];
- low = (arg - (high = arg)) * 1e9 + .5;
- }
- high += low >= 1000000000; /* carry from rounding */
-
- /* convert high//low to string */
- *(bufptr = buf + 19) = '\0';
- for (i = 0; ++i <= 9;) {
- split(low, 10);
- *(--bufptr) = r.rem + '0';
- low = r.quot;
- split(high, 10);
- *(bufptr - 9) = r.rem + '0';
- high = r.quot;
- }
- /* discard leading zero */
- for (totdigs = 18, bufptr -= 9; (bufptr[0] == '0') & (bufptr[1] != '\0'); ++bufptr)
- --totdigs;
- /* one trailing zero ought to be discarded, in the case where it
- ** is the result of rounding up, so that, if the carry goes all the way
- ** across, totdigs will not be greater than requested
- ** also, trailing zeros beyond DBL_DIG can degrade accuracy of conversion back to binary */
-
- *decexp = totdigs - (ffmt ? ndigs : scale);
-
- return bufptr;
- }
-